#include "stdafx.h"
#include "gp_Lin.h"
#include "gp_Ax3.h"
#include "gp_Pnt.h"
#include "gp_Dir.h"
#include "gp_Ax1.h"
#include "gp_Lin.h"
#include "gp_Ax2.h"
#include "gp_Trsf.h"
#include "gp_Vec.h"
#include "gp_Pln.h"
#include "gp.h"

gp_Pln::gp_Pln (const gp_Pnt& P,
	const gp_Dir& V)
{
	double A = V.X();
	double B = V.Y();
	double C = V.Z();
	double Aabs = A;
	if (Aabs < 0) Aabs = - Aabs;
	double Babs = B;
	if (Babs < 0) Babs = - Babs;
	double Cabs = C;
	if (Cabs < 0) Cabs = - Cabs;

	//  pour determiner l'axe X :
	//  on dit que le produit scalaire Vx.V = 0. 
	//  et on recherche le max(A,B,C) pour faire la division.
	//  l'une des coordonnees du vecteur est nulle. 

	if( Babs <= Aabs && Babs <= Cabs) {
		if (Aabs > Cabs)  pos = gp_Ax3 (P, V, gp_Dir (-C,0., A));
		else              pos = gp_Ax3 (P, V, gp_Dir ( C,0.,-A));
	}
	else if( Aabs <= Babs && Aabs <= Cabs) {
		if (Babs > Cabs)  pos = gp_Ax3 (P, V, gp_Dir (0.,-C, B));
		else              pos = gp_Ax3 (P, V, gp_Dir (0., C,-B));
	}
	else {
		if (Aabs > Babs)  pos = gp_Ax3 (P, V, gp_Dir (-B, A,0.));
		else              pos = gp_Ax3 (P, V, gp_Dir ( B,-A,0.));
	}
}

gp_Pln::gp_Pln (const double A,
	const double B,
	const double C,
	const double D)
{
	double Aabs = A;
	if (Aabs < 0) Aabs = - Aabs;
	double Babs = B;
	if (Babs < 0) Babs = - Babs;
	double Cabs = C;
	if (Cabs < 0) Cabs = - Cabs;
	if (Babs <= Aabs && Babs <= Cabs) {
		if (Aabs > Cabs) pos = gp_Ax3(gp_Pnt(-D/A,  0.,  0.),
			gp_Dir(A,B,C),
			gp_Dir(-C,0., A));
		else             pos = gp_Ax3(gp_Pnt(  0.,  0.,-D/C),
			gp_Dir(A,B,C),
			gp_Dir( C,0.,-A));
	}
	else if (Aabs <= Babs && Aabs <= Cabs) {
		if (Babs > Cabs) pos = gp_Ax3(gp_Pnt(  0.,-D/B,  0.),
			gp_Dir(A,B,C),
			gp_Dir(0.,-C, B));
		else             pos = gp_Ax3(gp_Pnt(  0.,  0.,-D/C),
			gp_Dir(A,B,C),
			gp_Dir(0., C,-B));
	}
	else {
		if (Aabs > Babs) pos = gp_Ax3(gp_Pnt(-D/A,  0.,  0.),
			gp_Dir(A,B,C),
			gp_Dir(-B, A, 0.));
		else             pos = gp_Ax3(gp_Pnt(  0.,-D/B,  0.),
			gp_Dir(A,B,C),
			gp_Dir( B,-A, 0.));
	}
} 

void gp_Pln::Mirror (const gp_Pnt& P)
{ pos.Mirror(P);  }

gp_Pln gp_Pln::Mirrored (const gp_Pnt& P) const
{
	gp_Pln Pl = *this;
	Pl.pos.Mirror(P);
	return Pl;
}

void gp_Pln::Mirror (const gp_Ax1& A1)
{ pos.Mirror(A1); }

gp_Pln gp_Pln::Mirrored (const gp_Ax1& A1) const
{
	gp_Pln Pl = *this;
	Pl.pos.Mirror(A1);
	return Pl;
}

void gp_Pln::Mirror (const gp_Ax2& A2)
{ pos.Mirror(A2); }

gp_Pln gp_Pln::Mirrored (const gp_Ax2& A2) const
{
	gp_Pln Pl = *this;
	Pl.pos.Mirror(A2);
	return Pl;
}
 gp_Pln::gp_Pln()
{ }

 gp_Pln::gp_Pln(const gp_Ax3& A3) : pos(A3)
{ }

 void gp_Pln::Coefficients (double& A,
				  double& B,
				  double& C,
				  double& D) const
{
  const gp_Dir& dir = pos.Direction();
  if (pos.Direct()) {
    A = dir.X();
    B = dir.Y();
    C = dir.Z();
  }
  else {
    A = -dir.X();
    B = -dir.Y();
    C = -dir.Z();
  }
  const gp_Pnt& P = pos.Location();
  D = -(A * P.X() + B * P.Y() + C * P.Z());
}

 void gp_Pln::SetAxis (const gp_Ax1& A1)
{ pos.SetAxis (A1); }

 void gp_Pln::SetLocation (const gp_Pnt& Loc)
{ pos.SetLocation (Loc); }

 void gp_Pln::SetPosition (const gp_Ax3& A3)
{ pos = A3; }

 void gp_Pln::UReverse ()
{ pos.XReverse(); }

 void gp_Pln::VReverse ()
{ pos.YReverse(); }

 bool gp_Pln::Direct()const
{ return pos.Direct(); }

 const gp_Ax1& gp_Pln::Axis() const
{ return pos.Axis(); }

 const gp_Pnt& gp_Pln::Location() const
{ return pos.Location(); }

   const gp_Ax3& gp_Pln::Position() const
{ return pos; }

 double gp_Pln::Distance(const gp_Pnt& P) const
{
  const gp_Pnt& loc = pos.Location ();
  const gp_Dir& dir = pos.Direction();
  double D = (dir.X() * (P.X() - loc.X()) +
		     dir.Y() * (P.Y() - loc.Y()) +
		     dir.Z() * (P.Z() - loc.Z()));
  if (D < 0) D = - D;
  return D;
}

 double gp_Pln::Distance (const gp_Lin& L)  const
{
  double D = 0.0;
  if ((pos.Direction()).IsNormal (L.Direction(), gp::Resolution())) {
    const gp_Pnt& P   = L  .Location ();
    const gp_Pnt& loc = pos.Location ();
    const gp_Dir& dir = pos.Direction();
    D = (dir.X() * (P.X() - loc.X()) +
	 dir.Y() * (P.Y() - loc.Y()) +
	 dir.Z() * (P.Z() - loc.Z()));
    if (D < 0) D = - D;
  }
  return D;
}

 double gp_Pln::Distance(const gp_Pln& Other) const
{
  double D = 0.0;
  if ((pos.Direction()).IsParallel(Other.pos.Direction(), gp::Resolution())){
    const gp_Pnt& P = Other.pos.Location();
    const gp_Pnt& loc = pos.Location ();
    const gp_Dir& dir = pos.Direction();
    D = (dir.X() * (P.X() - loc.X()) +
	 dir.Y() * (P.Y() - loc.Y()) +
	 dir.Z() * (P.Z() - loc.Z()));
    if (D < 0) D = - D;
  }
  return D;
}

 double gp_Pln::SquareDistance (const gp_Pnt& P) const
{ double D = Distance(P);   return D * D; }

 double gp_Pln::SquareDistance (const gp_Lin& L) const
{ double D = Distance(L);   return D * D; }

 double gp_Pln::SquareDistance (const gp_Pln& Other) const
{ double D = Distance(Other);   return D * D; }

 gp_Ax1 gp_Pln::XAxis () const
{ return gp_Ax1 (pos.Location(), pos.XDirection()); }

 gp_Ax1 gp_Pln::YAxis () const
{ return gp_Ax1 (pos.Location(), pos.YDirection()); }

 bool gp_Pln::Contains
(const gp_Pnt& P,
 const double LinearTolerance) const
{ return Distance(P) <= LinearTolerance; }

 bool gp_Pln::Contains
(const gp_Lin& L,
 const double LinearTolerance,
 const double AngularTolerance) const
{ return Contains(L.Location(), LinearTolerance) && 
    pos.Direction().IsNormal(L.Direction(), AngularTolerance);
}

 void gp_Pln::Rotate (const gp_Ax1& A1, const double Ang)
{ pos.Rotate(A1, Ang); }

 gp_Pln gp_Pln::Rotated (const gp_Ax1& A1,
			       const double Ang) const
{
  gp_Pln Pl = *this;
  Pl.pos.Rotate(A1, Ang);
  return Pl;
} 

 void gp_Pln::Scale (const gp_Pnt& P, const double S)
{ pos.Scale(P, S); }

 gp_Pln gp_Pln::Scaled (const gp_Pnt& P,
			      const double S) const
{
  gp_Pln Pl = *this;
  Pl.pos.Scale(P, S);
  return Pl;
}

 void gp_Pln::Transform (const gp_Trsf& T)
{ pos.Transform(T); }

 gp_Pln gp_Pln::Transformed (const gp_Trsf& T) const
{
  gp_Pln Pl = *this;
  Pl.pos.Transform(T);            
  return Pl;
}

 void gp_Pln::Translate (const gp_Vec& V)
{ pos.Translate(V); }

 gp_Pln gp_Pln::Translated (const gp_Vec& V) const
{
  gp_Pln Pl = *this;
  Pl.pos.Translate(V);
  return Pl;
}

 void gp_Pln::Translate (const gp_Pnt& P1, const gp_Pnt& P2)
{ pos.Translate(P1,P2); }

 gp_Pln gp_Pln::Translated (const gp_Pnt& P1,
				  const gp_Pnt& P2) const
{
  gp_Pln Pl = *this;
  Pl.pos.Translate(P1, P2);
  return Pl;
}

